package gui.fileImportWindow;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;

import core.ConstantRegexes;
import core.Constants;
import core.Person;
import dataBase.DbHolder;

public class CSVreader {

	private int totalLines;
	private final File file;
	private final String [][] parsedEntries;

	private final boolean running = true;

	public CSVreader(File file) throws IOException {
		this.file = file;
		this.totalLines = this.getNumberOfLines();
		this.parsedEntries = new String [this.totalLines] [];
		this.parseEntireFile();
	}

	/**
	 * @return total number of lines in csv-file
	 * @throws IOException
	 */
	public int getNumberOfLines() throws IOException {
		/** compute total number of lines */
		FileInputStream fileInputStream = new FileInputStream(this.file);
		DataInputStream dataInputStream = new DataInputStream(fileInputStream);
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));

		this.totalLines = 0;
		while (bufferedReader.readLine() != null) {
			this.totalLines++;
		}

		bufferedReader.close();
		dataInputStream.close();
		fileInputStream.close();

		return this.totalLines;
	}

	/**
	 * @param lineNumber
	 *            the line number in the csv-file
	 * @return the content as String-array or - in case of an exception, an
	 *         array of empty strings
	 * @throws IOException
	 */
	public String [] getLine(int lineNumber) throws IOException {
		if (lineNumber < this.getNumberOfLines()) {
			return this.parsedEntries [lineNumber];
		} else {
			return new String [] { "", "", "", "", "", "", "", "", "", "", "" };
		}
	}

	public boolean [] isValid(int lineNumber) throws IOException {
		return this.isValid(this.getLine(lineNumber));
	}

	public boolean [] isValid(String [] toCheck) {
		boolean [] toReturn = new boolean [11];
		for (int i = 0; i < toReturn.length; i++) {
			toReturn [0] = false;
		}

		toReturn [0] = toCheck [0].matches(ConstantRegexes.surNameRegEx); // surname
		// error
		toReturn [1] = toCheck [1].matches(ConstantRegexes.nameRegEx); // name
		// error
		toReturn [2] = toCheck [2].matches(ConstantRegexes.NationRegEx); // nation
		// error
		toReturn [3] = toCheck [3].matches(ConstantRegexes.CountryRegEx); // country
		// error
		toReturn [4] = toCheck [4].matches(ConstantRegexes.bowCathegoryRegEx); // bowcathegory
		// error
		toReturn [5] = toCheck [5].matches(ConstantRegexes.ageClassRegEx); // ageclass
		// error
		toReturn [6] = toCheck [6].matches(ConstantRegexes.clubRegEx); // club
		// error
		toReturn [7] = toCheck [7].matches(ConstantRegexes.genderRegEx); // gender
		// error
		toReturn [8] = toCheck [8].matches(ConstantRegexes.licenseRegEx); // license
		// error
		toReturn [9] = toCheck [9].matches(ConstantRegexes.countryRatingRegEx); // countryrating
		toReturn [10] = true;
		// error

		// String [] tmp = new Date("tmp").getDatePatterns();
		// String dateRegEx = "(" + tmp [0] + ")|(" + tmp [1] + ")|(" + tmp [2]
		// + ")|(" + tmp [3] + ")|(" + tmp [4] + ")";
		// toReturn [10] = toCheck [9].matches(dateRegEx); // date error

		return toReturn;
	}

	private void parseEntireFile() throws IOException {
		FileInputStream fileInputStream = new FileInputStream(this.file);
		DataInputStream dataInputStream = new DataInputStream(fileInputStream);
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(dataInputStream));

		String inputLine; // input line
		int lineNumber = 0; // line number
		while (((inputLine = bufferedReader.readLine()) != null)) {
			/** delete trailing semicolon */
			if (inputLine.matches(".*;")) {
				inputLine = inputLine.substring(0, inputLine.length() - 1);
			}

			/** insert parsed line into output array */
			this.parsedEntries [lineNumber] = inputLine.split(";");

			/**
			 * shorten all strings that are too long for the database (max 40
			 * chars)
			 */
			for (int i = 0; i < this.parsedEntries [lineNumber].length; i++) {
				if (this.parsedEntries [lineNumber] [i].length() > 40) {
					this.parsedEntries [lineNumber] [i] = this.parsedEntries [lineNumber] [i].substring(0, 39);
				}
			}

			/** maybe the age is missing? */
			if (this.parsedEntries [lineNumber].length == 10) {
				String [] tmp = this.parsedEntries [lineNumber].clone();
				this.parsedEntries [lineNumber] = new String [11];
				for (int i = 0; i < tmp.length; i++) {
					this.parsedEntries [lineNumber] [i] = tmp [i];
				}
				this.parsedEntries [lineNumber] [10] = "01.01.1900";
			}

			/** now all valid lines should have length 11 */

			if (this.parsedEntries [lineNumber].length == 11) {

				/** correct gender column */
				if (this.parsedEntries [lineNumber] [7].matches(ConstantRegexes.maleRegEx)) {
					this.parsedEntries [lineNumber] [7] = Constants.MALE;
				} else if (this.parsedEntries [lineNumber] [7].matches(ConstantRegexes.femaleRegEx)) {
					this.parsedEntries [lineNumber] [7] = Constants.FEMALE;
				}

				/** correct license column */
				if (this.parsedEntries [lineNumber] [8].matches(ConstantRegexes.trueValues)) {
					this.parsedEntries [lineNumber] [8] = "true";
				} else if (this.parsedEntries [lineNumber] [8].matches(ConstantRegexes.falseValues)) {
					this.parsedEntries [lineNumber] [8] = "false";
				}

				/** correct countryRating column if existent */
				if (this.parsedEntries [lineNumber] [9].matches(ConstantRegexes.trueValues)) {
					this.parsedEntries [lineNumber] [9] = "true";
				} else if (this.parsedEntries [lineNumber] [9].matches(ConstantRegexes.falseValues)) {
					this.parsedEntries [lineNumber] [9] = "false";
				}

			}

			lineNumber++;
		}
	}

	public boolean hasValidLength(int lineNumber) throws IOException {
		return this.hasValidLength(this.getLine(lineNumber));
	}

	/**
	 * @param toCheck
	 *            line of csv-file as string-array
	 * @return true if length = 11, false otherwise
	 */
	public boolean hasValidLength(String [] toCheck) {
		return (toCheck.length == 11);
	}

	private Person lineToPerson(int lineNumber) throws IOException {
		String [] tmp = this.getLine(lineNumber);

		String name = tmp [0];
		String surName = tmp [1];
		String nation = tmp [2];
		String country = tmp [3];
		String bowCathegory = tmp [4];
		String ageClass = tmp [5];
		String club = tmp [6];
		String gender = tmp [7];
		boolean license = new Boolean(tmp [8]);
		boolean countryRating = new Boolean(tmp [9]);
		String birthdate = tmp [10];

		return new Person(name, surName, nation, country, bowCathegory, ageClass, club, gender, license, countryRating, birthdate);
	}

	public boolean isAlreadyInDB(int lineNumber) throws IOException {
		return DbHolder.getInstance().getArcherData().personExistsAlready(this.lineToPerson(lineNumber));
	}

	public void saveLineToDB(int lineNumber) throws SQLException, IOException {
		DbHolder.getInstance().getArcherData().insertArcherWithoutNotify(this.lineToPerson(lineNumber));
	}
}
